/*
 * Copyright 2009 fearsomeJ.org
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.fearsomej.jayme.process;

import java.util.Collections;
import java.util.List;

/**
 * @author Kevin Beddingfield
 * 
 */
public class JaymeProcess implements ProcessStepAction {

	private String name;
	private List<Transition> transitions;

	public static final StartStep START = new StartStep();
	private static final String START_NAME = "jayme.start";
	private static final TransitionComparator transComparator = new TransitionComparator();

	// a special case step used to start the process execution
	private static final class StartStep implements ProcessStepAction {

		@Override
		public ExecutionContext execute(ExecutionContext context) {
			return context;
		}

		@Override
		public String getName() {
			return START_NAME;
		}
	}

	/**
	 * @see ProcessStepAction#execute(ExecutionContext)
	 */
	@Override
	public ExecutionContext execute(ExecutionContext context) {
		ProcessStepAction currentStep = JaymeProcess.START;
		while (findNextStep(currentStep) != null) {
			currentStep = findNextStep(currentStep);
			context = currentStep.execute(context);
		}
		return context;
	}

	//TODO kill the new operator in this method (possibly pool transitionToFind?)
	private ProcessStepAction findNextStep(ProcessStepAction currentStep) {
		ProcessStepAction nextStep = null;
		Transition transitionToFind = new Transition();
		transitionToFind.setFromStep(currentStep);
		int indexOfFoundTransition = Collections.binarySearch(transitions, transitionToFind, transComparator);
		if(indexOfFoundTransition >= 0) {
			Transition foundTransition = transitions.remove(indexOfFoundTransition);
			if (foundTransition.getDecisions() != null) {
				nextStep = evaluateDecisions(foundTransition);
				if (nextStep != null) {
					return nextStep;
				}
			} else {
				return foundTransition.getToStep();
			}
		}
		return nextStep;
	}

	private ProcessStepAction evaluateDecisions(Transition transition) {
		List<Decision> decisions = transition.getDecisions();
		for (Decision decision : decisions) {
			if (!decision.evaluatesToTrue()) {
				return null;
			}
		}
		return transition.getToStep();
	}

	/**
	 * @see ProcessStepAction#getName()
	 */
	@Override
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	/**
	 * 
	 * @param transitions
	 * @see Collections#sort()
	 */
	public void setTransitions(List<Transition> transitions) {
		Collections.sort(transitions, transComparator);
		this.transitions = transitions;
	}

}
